package cz.semjobKB.gui;

import com.vaadin.server.Page;
import com.vaadin.ui.*;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Upload.Receiver;
import com.vaadin.ui.Upload.SucceededEvent;
import com.vaadin.ui.Upload.SucceededListener;
import cz.semjobKB.controller.Controller;
import cz.semjobKB.virtuoso.utils.ETriplePart;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.OutputStream;

/**
 *  Provides controls to operate with the application
 */
@SuppressWarnings({ "restriction" })
@Component
public class ControlLayout extends VerticalLayout{
	
	public final String SEMJOB_FILES = System.getProperty( "user.home" ) + File.separator + "semjobFiles" + File.separator;
	public final String SEMJOB_DOCUMENTS = "documents";
	public final String SEMJOB_STRATEGY = "strategy";
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Autowired
	Controller controller;
	
	private VerticalLayout triplesLayout = new VerticalLayout();	
	private TextField subjectField = new TextField("Subject");
	private TextField predicateField = new TextField("Predicate");
	private TextField objectField = new TextField("Object");
	private Button findTriplesButton = new Button("Find Triple");
	private Button getTripleDetailsButton = new Button("Get Details");
	private Button searchDocumentTriplesButton = new Button("Search Document");
	
	VerticalLayout terminologyLayout = new VerticalLayout();
	private TextField terminologyField = new TextField("Terminology");
	private Button getTerminologyDetailsButton = new Button("Get Details");
	private Button searchDocumentTerminologyButton = new Button("Search Document");	
		
	private VerticalLayout uploadLayout = new VerticalLayout();
	private StrategyUploader receiverStrategy = new StrategyUploader();
	private DocumentUploader receiverDocument = new DocumentUploader();
	private Upload uploadStrategy = new Upload("Upload Strategy", receiverDocument);
	private Upload uploadDocument = new Upload("Upload Document", receiverDocument);	
	private ComboBox selectStrategy = new ComboBox("Select Strategy");	
	
	
	File folderDoc = new File ( SEMJOB_FILES +  SEMJOB_DOCUMENTS);
	File strategyFolder = new File ( SEMJOB_FILES + SEMJOB_STRATEGY);
		
	@PostConstruct
    protected void init() {		
		this.setWidth("100%");
		this.setMargin(true);
		initTriplesLayout();
		initTripleButtons();
		initTerminologyLayout();
		initTerminologyButtons();
		initUploadLayout();		
		triplesLayout.setMargin(true);
		terminologyLayout.setMargin(true);
		uploadLayout.setMargin(true);
		this.addComponent(triplesLayout);
		this.addComponent(terminologyLayout);
		this.addComponent(uploadLayout);		
	}

    /*
        Initializes layout for triples
     */
	private void initTriplesLayout() {
		triplesLayout.setSizeFull();
		triplesLayout.addComponent(subjectField);
		triplesLayout.addComponent(predicateField);
		triplesLayout.addComponent(objectField);
		HorizontalLayout horizontalLayout = new HorizontalLayout();
		findTriplesButton.setWidth("100%");
		getTripleDetailsButton.setWidth("100%");
		searchDocumentTriplesButton.setWidth("100%");
		horizontalLayout.addComponent(findTriplesButton);
		horizontalLayout.addComponent(getTripleDetailsButton);
		horizontalLayout.addComponent(searchDocumentTriplesButton);
		horizontalLayout.setSizeFull();
		triplesLayout.addComponent(horizontalLayout);		
	}

    /*
        Initializes buttons to operate with triples
     */
	private void initTripleButtons() {
		findTriplesButton.addClickListener(new ClickListener() {			
			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				controller.suggestTriples(subjectField.getValue(), predicateField.getValue(), objectField.getValue());				
			}
		});
		getTripleDetailsButton.addClickListener(new ClickListener() {			
			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				if (!subjectField.getValue().isEmpty()) {
					controller.resourceDetail(ETriplePart.SUBJECT, subjectField.getValue());				
				}
				if (!predicateField.getValue().isEmpty()) {
					controller.resourceDetail(ETriplePart.PREDICATE, predicateField.getValue());				
				}
				if (!objectField.getValue().isEmpty()) {
					controller.resourceDetail(ETriplePart.OBJECT, objectField.getValue());				
				}
			}
		});
		searchDocumentTriplesButton.addClickListener(new ClickListener() {			
			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				controller.findDocument(subjectField.getValue(), predicateField.getValue(), objectField.getValue());				
			}
		});
	}

    /*
        Initializes terminology layout
     */
	private void initTerminologyLayout() {
		terminologyLayout.addComponent(terminologyField);
		HorizontalLayout horizontalLayout = new HorizontalLayout();
		getTerminologyDetailsButton.setWidth("100%");
		searchDocumentTerminologyButton.setWidth("100%");
		horizontalLayout.addComponent(getTerminologyDetailsButton);
		horizontalLayout.addComponent(searchDocumentTerminologyButton);
		horizontalLayout.setSizeFull();
		terminologyLayout.addComponent(horizontalLayout);		
	}

    /*
        Initializes terminology buttons
     */
	private void initTerminologyButtons() {
		getTerminologyDetailsButton.addClickListener(new ClickListener() {
			
			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				controller.resourceDetail(null, terminologyField.getValue());
				
			}
		});
		
		searchDocumentTerminologyButton.addClickListener(new ClickListener() {
			
			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				controller.findDocument(terminologyField.getValue());				
			}
		});
	}

    /*
        Initializes upload layout, for strategy and files
     */
	private void initUploadLayout() {
		uploadStrategy.setButtonCaption("Upload");
		uploadStrategy.addSucceededListener(receiverStrategy);
		uploadDocument.addSucceededListener(receiverDocument);
		uploadDocument.setButtonCaption("Process");
		
		File folderStrategy = new File (SEMJOB_FILES + SEMJOB_STRATEGY);
		String[] strategyFiles;
		FilenameFilter filter = new FilenameFilter() {
	        public boolean accept(File directory, String fileName) {
	            return fileName.endsWith(".xml");
	        }
	    };
		strategyFiles = folderStrategy.list(filter);
		for (String file : strategyFiles) {
			selectStrategy.addItem(file);			
		}		
		
		selectStrategy.setNullSelectionAllowed(false);		
		selectStrategy.setValue(selectStrategy.getItemIds().iterator().next());
		uploadLayout.addComponent(selectStrategy);
		uploadLayout.addComponent(uploadStrategy);
		uploadLayout.addComponent(uploadDocument);
	}

    /**
     * Inner class for Strategy uploader class
     */
	class StrategyUploader implements Receiver, SucceededListener {
	    /**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		public File file;
	    
	    public OutputStream receiveUpload(String filename,
	                                      String mimeType) {
	        // Create upload stream
	        FileOutputStream fos = null; // Stream to write to
	        try {
	        	File folder;
	        	if("xml".equals(FilenameUtils.getExtension(filename))) {
	        		folder = new File ( SEMJOB_FILES + SEMJOB_STRATEGY);
	            } else {
	            	folder = folderDoc;
	            }
	            file = new File(folder, filename.replaceAll(" ", "_"));
	            fos = new FileOutputStream(file);
	        } catch (final java.io.FileNotFoundException e) {
	            new Notification("Could not open file:" + filename, 
	                             e.getMessage(),
	                             Notification.Type.ERROR_MESSAGE)
	                .show(Page.getCurrent());
	            return null;
	        }
	        return fos; // Return the output stream to write to
	    }

	    public void uploadSucceeded(SucceededEvent event) {
	    	init(); 
	    	new Notification("File transfer done!",                     
                     Notification.Type.HUMANIZED_MESSAGE)
        .show(Page.getCurrent());
	    	 
	    }
	};

    /**
     * Innire class for document uploader, after successful upload the processing of the document begins
     */
	class DocumentUploader implements Receiver, SucceededListener {
	    /**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		public File file;
	    
	    public OutputStream receiveUpload(String filename,
	                                      String mimeType) {
	        // Create upload stream
	        FileOutputStream fos = null; // Stream to write to
	        try {
	        	File folder = folderDoc;	            
	            file = new File(folder, filename.replaceAll(" ", "_"));
	            fos = new FileOutputStream(file);
	        } catch (final java.io.FileNotFoundException e) {
	            new Notification("Could not open file:" + filename, 
	                             e.getMessage(),
	                             Notification.Type.ERROR_MESSAGE)
	                .show(Page.getCurrent());
	            return null;
	        }
	        return fos; // Return the output stream to write to
	    }

	    public void uploadSucceeded(SucceededEvent event) {
	    	init();	    	
	    	new Notification("File transfer done! Document is being processed",                     
                     Notification.Type.HUMANIZED_MESSAGE).show(Page.getCurrent());
	    	
	    	String strategyName = (String)selectStrategy.getValue();				
			File fileStrategy = new File(strategyFolder, strategyName);
			File fileToProcess = new File(folderDoc.getAbsolutePath() + File.separator + event.getFilename());			
			controller.processDocument(fileToProcess, fileStrategy);
	    	 
	    }
	};
}
